home *** CD-ROM | disk | FTP | other *** search
/ The Arsenal Files 8 / The Arsenal Files Collection #8 (Arsenal Computer) (1996).ISO / g_quake / racnab20.zip / FRAGGREN.QC < prev    next >
Text File  |  1996-08-06  |  34KB  |  1,515 lines

  1. /*
  2.  
  3. Bouncing Fragmentation Grenade!    7/28/96 by Steve Bond
  4. Email: wedge@nuc.net    WWW: http://www.nuc.net/quake
  5.  
  6. >>>READ THE README!
  7.  
  8. Hey ID! 
  9. If you are reading this, PUH-LEEZE fly me and John to Texas!
  10. We'll scrub the shitters at id for the chance to shake hands!
  11. (I mean - we'll wash our hands first and everything)
  12.  
  13. */
  14.  
  15. void (entity targ, entity inflictor, entity attacker, float damage) T_Damage;
  16. void () player_run;
  17. void(entity bomb, entity attacker, float rad, entity ignore) T_RadiusDamage;
  18. void(vector org, vector vel, float damage) SpawnBlood;
  19. void() SuperDamageSound;
  20.  
  21.  
  22. // called by worldspawn
  23. void() W_Precache =
  24. {
  25.     precache_sound ("weapons/r_exp3.wav");  // new rocket explosion
  26.     precache_sound ("weapons/rocket1i.wav");        // spike gun
  27.     precache_sound ("weapons/sgun1.wav");
  28.     precache_sound ("weapons/guncock.wav"); // player shotgun
  29.     precache_sound ("weapons/ric1.wav");    // ricochet (used in c code)
  30.     precache_sound ("weapons/ric2.wav");    // ricochet (used in c code)
  31.     precache_sound ("weapons/ric3.wav");    // ricochet (used in c code)
  32.     precache_sound ("weapons/spike2.wav");  // super spikes
  33.     precache_sound ("weapons/tink1.wav");   // spikes tink (used in c code)
  34.     precache_sound ("weapons/grenade.wav"); // grenade launcher
  35.     precache_sound ("weapons/bounce.wav");          // grenade bounce
  36.     precache_sound ("weapons/shotgn2.wav"); // super shotgun
  37. };
  38.  
  39. float() crandom =
  40. {
  41.     return 2*(random() - 0.5);
  42. };
  43.  
  44. /*
  45. ================
  46. W_FireAxe
  47. ================
  48. */
  49. void() W_FireAxe =
  50. {
  51.     local   vector  source;
  52.     local   vector  org;
  53.  
  54.     source = self.origin + '0 0 16';
  55.     traceline (source, source + v_forward*64, FALSE, self);
  56.     if (trace_fraction == 1.0)
  57.         return;
  58.     
  59.     org = trace_endpos - v_forward*4;
  60.  
  61.     if (trace_ent.takedamage)
  62.     {
  63.         trace_ent.axhitme = 1;
  64.         SpawnBlood (org, '0 0 0', 20);
  65.         T_Damage (trace_ent, self, self, 20);
  66.     }
  67.     else
  68.     {       // hit wall
  69.         sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
  70.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  71.         WriteByte (MSG_BROADCAST, TE_GUNSHOT);
  72.         WriteCoord (MSG_BROADCAST, org_x);
  73.         WriteCoord (MSG_BROADCAST, org_y);
  74.         WriteCoord (MSG_BROADCAST, org_z);
  75.     }
  76. };
  77.  
  78.  
  79. //============================================================================
  80.  
  81.  
  82. vector() wall_velocity =
  83. {
  84.     local vector    vel;
  85.     
  86.     vel = normalize (self.velocity);
  87.     vel = normalize(vel + v_up*(random()- 0.5) + v_right*(random()- 0.5));
  88.     vel = vel + 2*trace_plane_normal;
  89.     vel = vel * 200;
  90.     
  91.     return vel;
  92. };
  93.  
  94.  
  95. /*
  96. ================
  97. SpawnMeatSpray
  98. ================
  99. */
  100. void(vector org, vector vel) SpawnMeatSpray =
  101. {
  102.     local   entity missile, mpuff;
  103.     local   vector  org;
  104.  
  105.     missile = spawn ();
  106.     missile.owner = self;
  107.     missile.movetype = MOVETYPE_BOUNCE;
  108.     missile.solid = SOLID_NOT;
  109.  
  110.     makevectors (self.angles);
  111.  
  112.     missile.velocity = vel;
  113.     missile.velocity_z = missile.velocity_z + 250 + 50*random();
  114.  
  115.     missile.avelocity = '3000 1000 2000';
  116.     
  117. // set missile duration
  118.     missile.nextthink = time + 1;
  119.     missile.think = SUB_Remove;
  120.  
  121.     setmodel (missile, "progs/zom_gib.mdl");
  122.     setsize (missile, '0 0 0', '0 0 0');            
  123.     setorigin (missile, org);
  124. };
  125.  
  126. /*
  127. ================
  128. SpawnBlood
  129. ================
  130. */
  131. void(vector org, vector vel, float damage) SpawnBlood =
  132. {
  133.     particle (org, vel*0.1, 73, damage*2);
  134. };
  135.  
  136. /*
  137. ================
  138. spawn_touchblood
  139. ================
  140. */
  141. void(float damage) spawn_touchblood =
  142. {
  143.     local vector    vel;
  144.  
  145.     vel = wall_velocity () * 0.2;
  146.     SpawnBlood (self.origin + vel*0.01, vel, damage);
  147. };
  148.  
  149.  
  150. /*
  151. ================
  152. SpawnChunk
  153. ================
  154. */
  155. void(vector org, vector vel) SpawnChunk =
  156. {
  157.     particle (org, vel*0.02, 0, 10);
  158. };
  159.  
  160. /*
  161. ==============================================================================
  162.  
  163. MULTI-DAMAGE
  164.  
  165. Collects multiple small damages into a single damage
  166.  
  167. ==============================================================================
  168. */
  169.  
  170. entity  multi_ent;
  171. float   multi_damage;
  172.  
  173. void() ClearMultiDamage =
  174. {
  175.     multi_ent = world;
  176.     multi_damage = 0;
  177. };
  178.  
  179. void() ApplyMultiDamage =
  180. {
  181.     if (!multi_ent)
  182.         return;
  183.     T_Damage (multi_ent, self, self, multi_damage);
  184. };
  185.  
  186. void(entity hit, float damage) AddMultiDamage =
  187. {
  188.     if (!hit)
  189.         return;
  190.     
  191.     if (hit != multi_ent)
  192.     {
  193.         ApplyMultiDamage ();
  194.         multi_damage = damage;
  195.         multi_ent = hit;
  196.     }
  197.     else
  198.         multi_damage = multi_damage + damage;
  199. };
  200.  
  201. /*
  202. ==============================================================================
  203.  
  204. BULLETS
  205.  
  206. ==============================================================================
  207. */
  208.  
  209. /*
  210. ================
  211. TraceAttack
  212. ================
  213. */
  214. void(float damage, vector dir) TraceAttack =
  215. {
  216.     local   vector  vel, org;
  217.     
  218.     vel = normalize(dir + v_up*crandom() + v_right*crandom());
  219.     vel = vel + 2*trace_plane_normal;
  220.     vel = vel * 200;
  221.  
  222.     org = trace_endpos - dir*4;
  223.  
  224.     if (trace_ent.takedamage)
  225.     {
  226.         SpawnBlood (org, vel*0.2, damage);
  227.         AddMultiDamage (trace_ent, damage);
  228.     }
  229.     else
  230.     {
  231.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  232.         WriteByte (MSG_BROADCAST, TE_GUNSHOT);
  233.         WriteCoord (MSG_BROADCAST, org_x);
  234.         WriteCoord (MSG_BROADCAST, org_y);
  235.         WriteCoord (MSG_BROADCAST, org_z);
  236.     }
  237. };
  238.  
  239. /*
  240. ================
  241. FireBullets
  242.  
  243. Used by shotgun, super shotgun, and enemy soldier firing
  244. Go to the trouble of combining multiple pellets into a single damage call.
  245. ================
  246. */
  247. void(float shotcount, vector dir, vector spread) FireBullets =
  248. {
  249.     local   vector direction;
  250.     local   vector  src;
  251.     
  252.     makevectors(self.v_angle);
  253.  
  254.     src = self.origin + v_forward*10;
  255.     src_z = self.absmin_z + self.size_z * 0.7;
  256.  
  257.     ClearMultiDamage ();
  258.     while (shotcount > 0)
  259.     {
  260.         direction = dir + crandom()*spread_x*v_right + crandom()*spread_y*v_up;
  261.  
  262.         traceline (src, src + direction*2048, FALSE, self);
  263.         if (trace_fraction != 1.0)
  264.             TraceAttack (4, direction);
  265.  
  266.         shotcount = shotcount - 1;
  267.     }
  268.     ApplyMultiDamage ();
  269. };
  270.  
  271. /*
  272. ================
  273. W_FireShotgun
  274. ================
  275. */
  276. void() W_FireShotgun =
  277. {
  278.     local vector dir;
  279.  
  280.     sound (self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM); 
  281.  
  282.     self.punchangle_x = -2;
  283.     
  284.     self.currentammo = self.ammo_shells = self.ammo_shells - 1;
  285.     dir = aim (self, 100000);
  286.     FireBullets (6, dir, '0.04 0.04 0');
  287. };
  288.  
  289.  
  290. /*
  291. ================
  292. W_FireSuperShotgun
  293. ================
  294. */
  295. void() W_FireSuperShotgun =
  296. {
  297.     local vector dir;
  298.  
  299.     if (self.currentammo == 1)
  300.     {
  301.         W_FireShotgun ();
  302.         return;
  303.     }
  304.         
  305.     sound (self ,CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM); 
  306.  
  307.     self.punchangle_x = -4;
  308.     
  309.     self.currentammo = self.ammo_shells = self.ammo_shells - 2;
  310.     dir = aim (self, 100000);
  311.     FireBullets (14, dir, '0.14 0.08 0');
  312. };
  313.  
  314.  
  315. /*
  316. ==============================================================================
  317.  
  318. ROCKETS
  319.  
  320. ==============================================================================
  321. */
  322.  
  323. void()  s_explode1      =       [0,             s_explode2] {};
  324. void()  s_explode2      =       [1,             s_explode3] {};
  325. void()  s_explode3      =       [2,             s_explode4] {};
  326. void()  s_explode4      =       [3,             s_explode5] {};
  327. void()  s_explode5      =       [4,             s_explode6] {};
  328. void()  s_explode6      =       [5,             SUB_Remove] {};
  329.  
  330. void() BecomeExplosion =
  331. {
  332.     self.movetype = MOVETYPE_NONE;
  333.     self.velocity = '0 0 0';
  334.     self.touch = SUB_Null;
  335.     setmodel (self, "progs/s_explod.spr");
  336.     self.solid = SOLID_NOT;
  337.     s_explode1 ();
  338. };
  339.  
  340. void() T_MissileTouch =
  341. {
  342.     local float     damg;
  343.  
  344.     if (other == self.owner)
  345.         return;         // don't explode on owner
  346.  
  347.     if (pointcontents(self.origin) == CONTENT_SKY)
  348.     {
  349.         remove(self);
  350.         return;
  351.     }
  352.  
  353.     damg = 100 + random()*20;
  354.     
  355.     if (other.health)
  356.     {
  357.         if (other.classname == "monster_shambler")
  358.             damg = damg * 0.5;      // mostly immune
  359.         T_Damage (other, self, self.owner, damg );
  360.     }
  361.  
  362.     // don't do radius damage to the other, because all the damage
  363.     // was done in the impact
  364.     T_RadiusDamage (self, self.owner, 120, other);
  365.  
  366. //      sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
  367.     self.origin = self.origin - 8*normalize(self.velocity);
  368.  
  369.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  370.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  371.     WriteCoord (MSG_BROADCAST, self.origin_x);
  372.     WriteCoord (MSG_BROADCAST, self.origin_y);
  373.     WriteCoord (MSG_BROADCAST, self.origin_z);
  374.  
  375.     BecomeExplosion ();
  376. };
  377.  
  378.  
  379.  
  380. /*
  381. ================
  382. W_FireRocket
  383. ================
  384. */
  385. void() W_FireRocket =
  386. {
  387.     local   entity missile, mpuff;
  388.     
  389.     self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  390.     
  391.     sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);
  392.  
  393.     self.punchangle_x = -2;
  394.  
  395.     missile = spawn ();
  396.     missile.owner = self;
  397.     missile.movetype = MOVETYPE_FLYMISSILE;
  398.     missile.solid = SOLID_BBOX;
  399.         
  400. // set missile speed    
  401.  
  402.     makevectors (self.v_angle);
  403.     missile.velocity = aim(self, 1000);
  404.     missile.velocity = missile.velocity * 1000;
  405.     missile.angles = vectoangles(missile.velocity);
  406.     
  407.     missile.touch = T_MissileTouch;
  408.     
  409. // set missile duration
  410.     missile.nextthink = time + 5;
  411.     missile.think = SUB_Remove;
  412.  
  413.     setmodel (missile, "progs/missile.mdl");
  414.     setsize (missile, '0 0 0', '0 0 0');            
  415.     setorigin (missile, self.origin + v_forward*8 + '0 0 16');
  416. };
  417.  
  418. /*
  419. ===============================================================================
  420.  
  421. LIGHTNING
  422.  
  423. ===============================================================================
  424. */
  425.  
  426. /*
  427. =================
  428. LightningDamage
  429. =================
  430. */
  431. void(vector p1, vector p2, entity from, float damage) LightningDamage =
  432. {
  433.     local entity            e1, e2;
  434.     local vector            f;
  435.     
  436.     f = p2 - p1;
  437.     normalize (f);
  438.     f_x = 0 - f_y;
  439.     f_y = f_x;
  440.     f_z = 0;
  441.     f = f*16;
  442.  
  443.     e1 = e2 = world;
  444.  
  445.     traceline (p1, p2, FALSE, self);
  446.     if (trace_ent.takedamage)
  447.     {
  448.         particle (trace_endpos, '0 0 100', 225, damage*4);
  449.         T_Damage (trace_ent, from, from, damage);
  450.         if (self.classname == "player")
  451.         {
  452.             if (other.classname == "player")
  453.                 trace_ent.velocity_z = trace_ent.velocity_z + 400;
  454.         }
  455.     }
  456.     e1 = trace_ent;
  457.  
  458.     traceline (p1 + f, p2 + f, FALSE, self);
  459.     if (trace_ent != e1 && trace_ent.takedamage)
  460.     {
  461.         particle (trace_endpos, '0 0 100', 225, damage*4);
  462.         T_Damage (trace_ent, from, from, damage);
  463.     }
  464.     e2 = trace_ent;
  465.  
  466.     traceline (p1 - f, p2 - f, FALSE, self);
  467.     if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage)
  468.     {
  469.         particle (trace_endpos, '0 0 100', 225, damage*4);
  470.         T_Damage (trace_ent, from, from, damage);
  471.     }
  472. };
  473.  
  474.  
  475. void() W_FireLightning =
  476. {
  477.     local   vector          org;
  478.  
  479.     if (self.ammo_cells < 1)
  480.     {
  481.         self.weapon = W_BestWeapon ();
  482.         W_SetCurrentAmmo ();
  483.         return;
  484.     }
  485.  
  486. // explode if under water
  487.     if (self.waterlevel > 1)
  488.     {
  489.         T_RadiusDamage (self, self, 35*self.ammo_cells, world);
  490.         self.ammo_cells = 0;
  491.         W_SetCurrentAmmo ();
  492.         return;
  493.     }
  494.  
  495.     if (self.t_width < time)
  496.     {
  497.         sound (self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM);
  498.         self.t_width = time + 0.6;
  499.     }
  500.     self.punchangle_x = -2;
  501.  
  502.     self.currentammo = self.ammo_cells = self.ammo_cells - 1;
  503.  
  504.     org = self.origin + '0 0 16';
  505.     
  506.     traceline (org, org + v_forward*600, TRUE, self);
  507.  
  508.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  509.     WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
  510.     WriteEntity (MSG_BROADCAST, self);
  511.     WriteCoord (MSG_BROADCAST, org_x);
  512.     WriteCoord (MSG_BROADCAST, org_y);
  513.     WriteCoord (MSG_BROADCAST, org_z);
  514.     WriteCoord (MSG_BROADCAST, trace_endpos_x);
  515.     WriteCoord (MSG_BROADCAST, trace_endpos_y);
  516.     WriteCoord (MSG_BROADCAST, trace_endpos_z);
  517.  
  518.     LightningDamage (self.origin, trace_endpos + v_forward*4, self, 30);
  519. };
  520.  
  521.  
  522. //=============================================================================
  523.  
  524.  
  525. void() GrenadeExplode =
  526. {
  527.     T_RadiusDamage (self, self.owner, 120, world);
  528.  
  529.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  530.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  531.     WriteCoord (MSG_BROADCAST, self.origin_x);
  532.     WriteCoord (MSG_BROADCAST, self.origin_y);
  533.     WriteCoord (MSG_BROADCAST, self.origin_z);
  534.  
  535.     BecomeExplosion ();
  536. };
  537.  
  538. void() GrenadeTouch =
  539. {
  540.     if (other == self.owner)
  541.         return;         // don't explode on owner
  542.     if (other.takedamage == DAMAGE_AIM)
  543.     {
  544.         GrenadeExplode();
  545.         return;
  546.     }
  547.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);  // bounce sound
  548.     if (self.velocity == '0 0 0')
  549.         self.avelocity = '0 0 0';
  550. };
  551.  
  552. /*
  553. ================
  554. W_FireGrenade
  555. ================
  556. */
  557. void() W_FireGrenade =
  558. {
  559.     local   entity missile, mpuff;
  560.     
  561.     self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  562.     
  563.     sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
  564.  
  565.     self.punchangle_x = -2;
  566.  
  567.     missile = spawn ();
  568.     missile.owner = self;
  569.     missile.movetype = MOVETYPE_BOUNCE;
  570.     missile.solid = SOLID_BBOX;
  571.     missile.classname = "grenade";
  572.         
  573. // set missile speed    
  574.  
  575.     makevectors (self.v_angle);
  576.  
  577.     if (self.v_angle_x)
  578.         missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
  579.     else
  580.     {
  581.         missile.velocity = aim(self, 10000);
  582.         missile.velocity = missile.velocity * 600;
  583.         missile.velocity_z = 200;
  584.     }
  585.  
  586.     missile.avelocity = '300 300 300';
  587.  
  588.     missile.angles = vectoangles(missile.velocity);
  589.     
  590.     missile.touch = GrenadeTouch;
  591.     
  592. // set missile duration
  593.     missile.nextthink = time + 2.5;
  594.     missile.think = GrenadeExplode;
  595.  
  596.     setmodel (missile, "progs/grenade.mdl");
  597.     setsize (missile, '0 0 0', '0 0 0');            
  598.     setorigin (missile, self.origin);
  599. };
  600.  
  601.  
  602. //=============================================================================
  603.  
  604. void() spike_touch;
  605. void() superspike_touch;
  606.  
  607.  
  608. /*
  609. ===============
  610. launch_spike
  611.  
  612. Used for both the player and the ogre
  613. ===============
  614. */
  615. void(vector org, vector dir) launch_spike =
  616. {
  617.     newmis = spawn ();
  618.     newmis.owner = self;
  619.     newmis.movetype = MOVETYPE_FLYMISSILE;
  620.     newmis.solid = SOLID_BBOX;
  621.  
  622.     newmis.angles = vectoangles(dir);
  623.     
  624.     newmis.touch = spike_touch;
  625.     newmis.classname = "spike";
  626.     newmis.think = SUB_Remove;
  627. // Bump the nail's lifespan up to 11 seconds(?),so it will stick for a bit        
  628.     newmis.nextthink = time + 11;
  629.     setmodel (newmis, "progs/spike.mdl");
  630.     setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);               
  631.     setorigin (newmis, org);
  632.  
  633.     newmis.velocity = dir * 1000;
  634. };
  635.  
  636. void() W_FireSuperSpikes =
  637. {
  638.     local vector    dir;
  639.     local entity    old;
  640.     
  641.     sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM);
  642.     self.attack_finished = time + 0.2;
  643.     self.currentammo = self.ammo_nails = self.ammo_nails - 2;
  644.     dir = aim (self, 1000);
  645.     launch_spike (self.origin + '0 0 16', dir);
  646.     newmis.touch = superspike_touch;
  647.     setmodel (newmis, "progs/s_spike.mdl");
  648.     setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);               
  649.     self.punchangle_x = -2;
  650. };
  651.  
  652. void(float ox) W_FireSpikes =
  653. {
  654.     local vector    dir;
  655.     local entity    old;
  656.     
  657.     makevectors (self.v_angle);
  658.     
  659.     if (self.ammo_nails >= 2 && self.weapon == IT_SUPER_NAILGUN)
  660.     {
  661.         W_FireSuperSpikes ();
  662.         return;
  663.     }
  664.  
  665.     if (self.ammo_nails < 1)
  666.     {
  667.         self.weapon = W_BestWeapon ();
  668.         W_SetCurrentAmmo ();
  669.         return;
  670.     }
  671.  
  672.     sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
  673.     self.attack_finished = time + 0.2;
  674.     self.currentammo = self.ammo_nails = self.ammo_nails - 1;
  675.     dir = aim (self, 1000);
  676.     launch_spike (self.origin + '0 0 16' + v_right*ox, dir);
  677.  
  678.     self.punchangle_x = -2;
  679. };
  680.  
  681.  
  682.  
  683. .float hit_z;
  684. void() spike_touch =
  685. {
  686. local float rand;
  687.     if (other == self.owner)
  688.         return;
  689.  
  690.     if (other.solid == SOLID_TRIGGER)
  691.         return; // trigger field, do nothing
  692.  
  693.     if (pointcontents(self.origin) == CONTENT_SKY)
  694.     {
  695.         remove(self);
  696.         return;
  697.     }
  698.     
  699. // hit something that bleeds
  700.     if (other.takedamage)
  701.     {
  702.         spawn_touchblood (9);
  703.         T_Damage (other, self, self.owner, 9);
  704.         remove(self);
  705.     }
  706.     else
  707.     {
  708.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  709.         
  710.         if (self.classname == "wizspike")
  711.             WriteByte (MSG_BROADCAST, TE_WIZSPIKE);
  712.         else if (self.classname == "knightspike")
  713.             WriteByte (MSG_BROADCAST, TE_KNIGHTSPIKE);
  714.         else
  715.             WriteByte (MSG_BROADCAST, TE_SPIKE);
  716.         WriteCoord (MSG_BROADCAST, self.origin_x);
  717.         WriteCoord (MSG_BROADCAST, self.origin_y);
  718.         WriteCoord (MSG_BROADCAST, self.origin_z);
  719.     }
  720.  
  721. /*
  722. DO NOT let the nail remove itself. This section of code is only executed
  723. when the nail has hit a wall, floor, or plat. These are places we want the 
  724. nail to stick, so we comment out the REMOVE(SELF); function call
  725. */
  726.     self.velocity='0 0 0'; // make the nail stop!
  727.     //remove(self);
  728.  
  729. };
  730.  
  731. void() superspike_touch =
  732. {
  733. local float rand;
  734.     if (other == self.owner)
  735.         return;
  736.  
  737.     if (other.solid == SOLID_TRIGGER)
  738.         return; // trigger field, do nothing
  739.  
  740.     if (pointcontents(self.origin) == CONTENT_SKY)
  741.     {
  742.         remove(self);
  743.         return;
  744.     }
  745.     
  746. // hit something that bleeds
  747.     if (other.takedamage)
  748.     {
  749.         spawn_touchblood (18);
  750.         T_Damage (other, self, self.owner, 18);
  751.     }
  752.     else
  753.     {
  754.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  755.         WriteByte (MSG_BROADCAST, TE_SUPERSPIKE);
  756.         WriteCoord (MSG_BROADCAST, self.origin_x);
  757.         WriteCoord (MSG_BROADCAST, self.origin_y);
  758.         WriteCoord (MSG_BROADCAST, self.origin_z);
  759.     }
  760.  
  761.     remove(self);
  762.  
  763. };
  764.  
  765.  
  766.  
  767.  
  768.  
  769.  
  770. /*========================================================================
  771. BOUNCING FRAGMENTATION GRENADE - Version .9
  772. 7/28/96 - Steve Bond  email:wedge@nuc.net
  773. http://www.nuc.net/quake
  774. =======================================================================*/
  775.  
  776. //This code segment handles the impact of shrapnel
  777. //this is merely id's superspike_touch code, reworked
  778. void() shrapnel_touch =
  779. {
  780. local float rand;
  781. // has the shrapnel hit a switch? 
  782.     if (other.solid == SOLID_TRIGGER)
  783.         return; // trigger field, do nothing
  784.  
  785. // has the shrapnel hit the sky?
  786.     if (pointcontents(self.origin) == CONTENT_SKY)
  787.     {
  788.         remove(self);
  789.         return;
  790.     }
  791.     
  792. // has the shrapnel hit a living thing?
  793.     if (other.takedamage)
  794.     {
  795.         spawn_touchblood (33);
  796.         T_Damage (other, self, self.owner, 33);
  797.     }
  798.     else
  799.     {
  800.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  801.         WriteByte (MSG_BROADCAST, TE_SUPERSPIKE);
  802.         WriteCoord (MSG_BROADCAST, self.origin_x);
  803.         WriteCoord (MSG_BROADCAST, self.origin_y);
  804.         WriteCoord (MSG_BROADCAST, self.origin_z);
  805.     }
  806.     remove(self);
  807. };
  808.  
  809. /*
  810. Code to spawn ONE randomly directed piece of shrapnel
  811. this is id's launch_spike code, reworked
  812. Pass a vector to this function to determine the shrap's origin
  813. */
  814. void (vector org, float spin) launch_shrapnel=
  815. {
  816.     local float xdir,ydir,zdir;
  817.     
  818. //Assign a random direction for the shrapnel to fly in
  819.     xdir = 110 * random() - 55;
  820.     ydir = 110 * random() - 55;
  821.     zdir = 50 * random() - 25;
  822.  
  823.     newmis = spawn ();
  824.     newmis.owner = self;
  825.     newmis.movetype = MOVETYPE_BOUNCE;
  826.     self.touch = SUB_Null;
  827.     newmis.solid = SOLID_BBOX;
  828.  
  829.     newmis.touch = shrapnel_touch;
  830.     newmis.classname = "spike";
  831.     newmis.think = SUB_Remove;
  832.     
  833. // this is how many seconds(?) the nails can exist.        
  834.     newmis.nextthink = time + 6;
  835.     
  836. // speed at which to move the shrapnel        
  837.     newmis.velocity_x = xdir * 5;
  838.     newmis.velocity_y = ydir * 5;
  839.     newmis.velocity_z = zdir * 4;
  840.  
  841. /*
  842. as best I can figure, AVELOCITY means "attitude velocity"        
  843. or something thereabouts. Anyway, it makes shit spin on 
  844. the x,y,z axes by the given velocity for each axis. In this 
  845. case, it makes the shrapnel spin in flight. Good stuff.
  846. this segment assigns one of five preset attitudes for 
  847. each piece of shrapnel, based on the number passed to the
  848. function.
  849. */        
  850.     if (spin == 0)
  851.     newmis.avelocity='250 300 400';
  852.     if (spin == 1)
  853.     newmis.avelocity='400 250 300';
  854.     if (spin == 2)
  855.     newmis.avelocity='300 400 250';
  856.     if (spin == 3)
  857.     newmis.avelocity='300 300 300';
  858.     if (spin == 4) 
  859.     newmis.avelocity='400 250 400';
  860.  
  861.     setmodel (newmis, "progs/s_spike.mdl");
  862.     setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
  863.     setorigin (newmis, org);
  864. };
  865.  
  866. // This code segment detonates the 'second stage' of the grenade
  867. // (After it has popped up)
  868. void()  BouncerExplode =
  869. {
  870.     
  871. // Do the damage
  872.     T_RadiusDamage (self, self.owner, 120, world);
  873. // Tell the network
  874.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  875.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  876.     WriteCoord (MSG_BROADCAST, self.origin_x);
  877.     WriteCoord (MSG_BROADCAST, self.origin_y);
  878.     WriteCoord (MSG_BROADCAST, self.origin_z);
  879.  
  880. // Let Quake handle the explosion and deallocation of the grenade        
  881.     self.solid=SOLID_NOT;
  882.     BecomeExplosion ();
  883.  
  884. // Launch a hail (20 pieces) of shrapnel
  885.     launch_shrapnel (self.origin + '0 0 -1',0);
  886.     launch_shrapnel (self.origin + '0 0 -1',1);
  887.     launch_shrapnel (self.origin + '0 0 -1',2);
  888.     launch_shrapnel (self.origin + '0 0 -1',3);
  889.     launch_shrapnel (self.origin + '0 0 -1',4);
  890.     launch_shrapnel (self.origin + '0 0 -1',0);
  891.     launch_shrapnel (self.origin + '0 0 -1',1);
  892.     launch_shrapnel (self.origin + '0 0 -1',2);
  893.     launch_shrapnel (self.origin + '0 0 -1',3);
  894.     launch_shrapnel (self.origin + '0 0 -1',4);
  895.     launch_shrapnel (self.origin + '0 0 -1',0);
  896.     launch_shrapnel (self.origin + '0 0 -1',1);
  897.     launch_shrapnel (self.origin + '0 0 -1',2);
  898.     launch_shrapnel (self.origin + '0 0 -1',3);
  899.     launch_shrapnel (self.origin + '0 0 -1',4);
  900.     launch_shrapnel (self.origin + '0 0 -1',0);
  901.     launch_shrapnel (self.origin + '0 0 -1',1);
  902.     launch_shrapnel (self.origin + '0 0 -1',2);
  903.     launch_shrapnel (self.origin + '0 0 -1',3);
  904.     launch_shrapnel (self.origin + '0 0 -1',4);
  905. };
  906.  
  907. /*
  908. This code segment makes the 'first stage' of the bouncer pop upward
  909. after it's time has expired.
  910. */
  911. void() BouncerPopUp=
  912. {
  913.     local entity missile, mpuff;
  914.  
  915. // Make the grenade stop
  916.     self.movetype=MOVETYPE_NONE;
  917.     self.velocity='0 0 0';
  918. // Draw a tiny explosion (no particles)        
  919.     setmodel (self, "progs/s_explod.spr");
  920.     s_explode1 ();
  921. // Make the :FOOMP: grenade launcher sound        
  922.     sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
  923. // Spawn and animate the 'second stage'
  924.     missile = spawn ();
  925.     missile.owner = self;
  926.     missile.movetype = MOVETYPE_BOUNCE;
  927.     missile.solid = SOLID_BBOX;
  928.     missile.classname = "grenade";
  929. // Set speed
  930.     missile.velocity = '0 0 650';
  931.     missile.angles = vectoangles(missile.velocity);
  932.     missile.touch = BouncerExplode;
  933. // Set Duration
  934.     missile.nextthink = time + 1;
  935.     missile.think = BouncerExplode;
  936.  
  937.     setmodel (missile, "progs/missile.mdl");
  938.     setsize (missile, '0 0 0', '0 0 0');
  939.     setorigin (missile, self.origin);
  940. };
  941.  
  942. // This code segment handles collisions for the 'first stage'
  943. // Of the grenade (after launch and before popup)
  944.  
  945. void() BouncerTouch =
  946. {
  947. //Did the grenade hit a 'living' thing?
  948.     if (other.takedamage)
  949.     {
  950. // yes, so play the bounce sound
  951.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
  952. // now, exit the function without cause damage to the thing        
  953.     return;
  954.     }
  955.  
  956. // This controls what happens when the grenade hits walls, etz        
  957. // It just plays the sound and bounces on
  958.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
  959.     if (self.velocity == '0 0 0')
  960.         self.avelocity = '0 0 0';
  961. };
  962.  
  963. /*
  964. This code segment handles the launching of the Bouncing Fragmentation Grenade
  965. this is a reworked copy of id's W_launchgrenade code
  966. */
  967. void() W_LaunchBouncer =
  968. {
  969. // If player doesn't have 3 or more rockets, don't launch
  970.     if (self.ammo_rockets < 3)
  971.     {
  972.     return;
  973.     }
  974.  
  975.     local   entity missile, mpuff;
  976.     
  977. // Take 3 rockets from the player        
  978.     self.currentammo = self.ammo_rockets = self.ammo_rockets - 3;
  979.     
  980.     //sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
  981. /*
  982. self.punchangle_x (x, y, or z) defines how hard the weapon         
  983. recoils (or 'punches' the player, making the screen shake)
  984. */        
  985.     self.punchangle_x = -2;
  986.  
  987. // This spawns the grenade - it is all id's standard grenade code        
  988.     missile = spawn ();
  989.     missile.owner = self;
  990.     missile.movetype = MOVETYPE_BOUNCE;
  991.     missile.solid = SOLID_BBOX;
  992.     missile.classname = "grenade";
  993.         
  994. // set missile speed    
  995.  
  996.     makevectors (self.v_angle);
  997.  
  998.     if (self.v_angle_x)
  999.         missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
  1000.     else
  1001.     {
  1002.         missile.velocity = aim(self, 10000);
  1003.         missile.velocity = missile.velocity * 600;
  1004.         missile.velocity_z = 200;
  1005.     }
  1006.  
  1007.     missile.avelocity = '300 300 300';
  1008.  
  1009.     missile.angles = vectoangles(missile.velocity);
  1010.     
  1011. // if the grenade touches anything, BouncerTouch() is called        
  1012.     missile.touch = BouncerTouch;
  1013.     
  1014. // Grenade has a maximum lifespan of 1.5 (seconds?)
  1015. // set missile duration
  1016.     missile.nextthink = time + 1.5;
  1017.     
  1018. // when the grenade's lifespan has expired, BouncerPopUp() is called        
  1019.     missile.think = BouncerPopUp;
  1020.  
  1021.     setmodel (missile, "progs/grenade.mdl");
  1022.     setsize (missile, '0 0 0', '0 0 0');            
  1023.     setorigin (missile, self.origin);
  1024. };
  1025. /*
  1026. ===============================================================================
  1027. End of Bouncing Fragmentation Grenade code.
  1028. ===============================================================================
  1029. */
  1030.  
  1031.  
  1032.  
  1033.  
  1034.  
  1035.  
  1036. /*
  1037.  
  1038. PLAYER WEAPON USE
  1039.  
  1040. ===============================================================================
  1041. */
  1042.  
  1043. void() W_SetCurrentAmmo =
  1044. {
  1045.     player_run ();          // get out of any weapon firing states
  1046.  
  1047.     self.items = self.items - ( self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS) );
  1048.     
  1049.     if (self.weapon == IT_AXE)
  1050.     {
  1051.         self.currentammo = 0;
  1052.         self.weaponmodel = "progs/v_axe.mdl";
  1053.         self.weaponframe = 0;
  1054.     }
  1055.     else if (self.weapon == IT_SHOTGUN)
  1056.     {
  1057.         self.currentammo = self.ammo_shells;
  1058.         self.weaponmodel = "progs/v_shot.mdl";
  1059.         self.weaponframe = 0;
  1060.         self.items = self.items | IT_SHELLS;
  1061.     }
  1062.     else if (self.weapon == IT_SUPER_SHOTGUN)
  1063.     {
  1064.         self.currentammo = self.ammo_shells;
  1065.         self.weaponmodel = "progs/v_shot2.mdl";
  1066.         self.weaponframe = 0;
  1067.         self.items = self.items | IT_SHELLS;
  1068.     }
  1069.     else if (self.weapon == IT_NAILGUN)
  1070.     {
  1071.         self.currentammo = self.ammo_nails;
  1072.         self.weaponmodel = "progs/v_nail.mdl";
  1073.         self.weaponframe = 0;
  1074.         self.items = self.items | IT_NAILS;
  1075.     }
  1076.     else if (self.weapon == IT_SUPER_NAILGUN)
  1077.     {
  1078.         self.currentammo = self.ammo_nails;
  1079.         self.weaponmodel = "progs/v_nail2.mdl";
  1080.         self.weaponframe = 0;
  1081.         self.items = self.items | IT_NAILS;
  1082.     }
  1083.     else if (self.weapon == IT_GRENADE_LAUNCHER)
  1084.     {
  1085.         self.currentammo = self.ammo_rockets;
  1086.         self.weaponmodel = "progs/v_rock.mdl";
  1087.         self.weaponframe = 0;
  1088.         self.items = self.items | IT_ROCKETS;
  1089.     }
  1090.     else if (self.weapon == IT_ROCKET_LAUNCHER)
  1091.     {
  1092.         self.currentammo = self.ammo_rockets;
  1093.         self.weaponmodel = "progs/v_rock2.mdl";
  1094.         self.weaponframe = 0;
  1095.         self.items = self.items | IT_ROCKETS;
  1096.     }
  1097.     else if (self.weapon == IT_LIGHTNING)
  1098.     {
  1099.         self.currentammo = self.ammo_cells;
  1100.         self.weaponmodel = "progs/v_light.mdl";
  1101.         self.weaponframe = 0;
  1102.         self.items = self.items | IT_CELLS;
  1103.     }
  1104.     else
  1105.     {
  1106.         self.currentammo = 0;
  1107.         self.weaponmodel = "";
  1108.         self.weaponframe = 0;
  1109.     }
  1110. };
  1111.  
  1112. float() W_BestWeapon =
  1113. {
  1114.     local   float   it;
  1115.     
  1116.     it = self.items;
  1117.  
  1118.     if(self.ammo_cells >= 1 && (it & IT_LIGHTNING) )
  1119.         return IT_LIGHTNING;
  1120.     else if(self.ammo_nails >= 2 && (it & IT_SUPER_NAILGUN) )
  1121.         return IT_SUPER_NAILGUN;
  1122.     else if(self.ammo_shells >= 2 && (it & IT_SUPER_SHOTGUN) )
  1123.         return IT_SUPER_SHOTGUN;
  1124.     else if(self.ammo_nails >= 1 && (it & IT_NAILGUN) )
  1125.         return IT_NAILGUN;
  1126.     else if(self.ammo_shells >= 1 && (it & IT_SHOTGUN) )
  1127.         return IT_SHOTGUN;
  1128.         
  1129. /*
  1130.     if(self.ammo_rockets >= 1 && (it & IT_ROCKET_LAUNCHER) )
  1131.         return IT_ROCKET_LAUNCHER;
  1132.     else if(self.ammo_rockets >= 1 && (it & IT_GRENADE_LAUNCHER) )
  1133.         return IT_GRENADE_LAUNCHER;
  1134.  
  1135. */
  1136.  
  1137.     return IT_AXE;
  1138. };
  1139.  
  1140. float() W_CheckNoAmmo =
  1141. {
  1142.     if (self.currentammo > 0)
  1143.         return TRUE;
  1144.  
  1145.     if (self.weapon == IT_AXE)
  1146.         return TRUE;
  1147.     
  1148.     self.weapon = W_BestWeapon ();
  1149.  
  1150.     W_SetCurrentAmmo ();
  1151.     
  1152. // drop the weapon down
  1153.     return FALSE;
  1154. };
  1155.  
  1156. /*
  1157. ============
  1158. W_Attack
  1159.  
  1160. An attack impulse can be triggered now
  1161. ============
  1162. */
  1163. void()  player_axe1;
  1164. void()  player_axeb1;
  1165. void()  player_axec1;
  1166. void()  player_axed1;
  1167. void()  player_shot1;
  1168. void()  player_nail1;
  1169. void()  player_light1;
  1170. void()  player_rocket1;
  1171.  
  1172. void() W_Attack =
  1173. {
  1174.     local   float   r;
  1175.  
  1176.     if (!W_CheckNoAmmo ())
  1177.         return;
  1178.  
  1179.     makevectors     (self.v_angle);                 // calculate forward angle for velocity
  1180.     self.show_hostile = time + 1;   // wake monsters up
  1181.  
  1182.     if (self.weapon == IT_AXE)
  1183.     {
  1184.         sound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM);
  1185.         r = random();
  1186.         if (r < 0.25)
  1187.             player_axe1 ();
  1188.         else if (r<0.5)
  1189.             player_axeb1 ();
  1190.         else if (r<0.75)
  1191.             player_axec1 ();
  1192.         else
  1193.             player_axed1 ();
  1194.         self.attack_finished = time + 0.5;
  1195.     }
  1196.     else if (self.weapon == IT_SHOTGUN)
  1197.     {
  1198.         player_shot1 ();
  1199.         W_FireShotgun ();
  1200.         self.attack_finished = time + 0.5;
  1201.     }
  1202.     else if (self.weapon == IT_SUPER_SHOTGUN)
  1203.     {
  1204.         player_shot1 ();
  1205.         W_FireSuperShotgun ();
  1206.         self.attack_finished = time + 0.7;
  1207.     }
  1208.     else if (self.weapon == IT_NAILGUN)
  1209.     {
  1210.         player_nail1 ();
  1211.     }
  1212.     else if (self.weapon == IT_SUPER_NAILGUN)
  1213.     {
  1214.         player_nail1 ();
  1215.     }
  1216.     else if (self.weapon == IT_GRENADE_LAUNCHER)
  1217.     {
  1218.         player_rocket1();
  1219.         W_FireGrenade();
  1220.         self.attack_finished = time + 0.6;
  1221.     }
  1222.     else if (self.weapon == IT_ROCKET_LAUNCHER)
  1223.     {
  1224.         player_rocket1();
  1225.         W_FireRocket();
  1226.         self.attack_finished = time + 0.8;
  1227.     }
  1228.     else if (self.weapon == IT_LIGHTNING)
  1229.     {
  1230.         player_light1();
  1231.         self.attack_finished = time + 0.1;
  1232.         sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
  1233.     }
  1234. };
  1235.  
  1236. /*
  1237. ============
  1238. W_ChangeWeapon
  1239.  
  1240. ============
  1241. */
  1242. void() W_ChangeWeapon =
  1243. {
  1244.     local   float   it, am, fl;
  1245.     
  1246.     it = self.items;
  1247.     am = 0;
  1248.     
  1249.     if (self.impulse == 1)
  1250.     {
  1251.         fl = IT_AXE;
  1252.     }
  1253.     else if (self.impulse == 2)
  1254.     {
  1255.         fl = IT_SHOTGUN;
  1256.         if (self.ammo_shells < 1)
  1257.             am = 1;
  1258.     }
  1259.     else if (self.impulse == 3)
  1260.     {
  1261.         fl = IT_SUPER_SHOTGUN;
  1262.         if (self.ammo_shells < 2)
  1263.             am = 1;
  1264.     }               
  1265.     else if (self.impulse == 4)
  1266.     {
  1267.         fl = IT_NAILGUN;
  1268.         if (self.ammo_nails < 1)
  1269.             am = 1;
  1270.     }
  1271.     else if (self.impulse == 5)
  1272.     {
  1273.         fl = IT_SUPER_NAILGUN;
  1274.         if (self.ammo_nails < 2)
  1275.             am = 1;
  1276.     }
  1277.     else if (self.impulse == 6)
  1278.     {
  1279.         fl = IT_GRENADE_LAUNCHER;
  1280.         if (self.ammo_rockets < 1)
  1281.             am = 1;
  1282.     }
  1283.     else if (self.impulse == 7)
  1284.     {
  1285.         fl = IT_ROCKET_LAUNCHER;
  1286.         if (self.ammo_rockets < 1)
  1287.             am = 1;
  1288.     }
  1289.     else if (self.impulse == 8)
  1290.     {
  1291.         fl = IT_LIGHTNING;
  1292.         if (self.ammo_cells < 1)
  1293.             am = 1;
  1294.     }
  1295.  
  1296.     self.impulse = 0;
  1297.     
  1298.     if (!(self.items & fl))
  1299.     {       // don't have the weapon or the ammo
  1300.         sprint (self, "no weapon.\n");
  1301.         return;
  1302.     }
  1303.     
  1304.     if (am)
  1305.     {       // don't have the ammo
  1306.         sprint (self, "not enough ammo.\n");
  1307.         return;
  1308.     }
  1309.  
  1310. //
  1311. // set weapon, set ammo
  1312. //
  1313.     self.weapon = fl;               
  1314.     W_SetCurrentAmmo ();
  1315. };
  1316.  
  1317. /*
  1318. ============
  1319. CheatCommand
  1320. ============
  1321. */
  1322. void() CheatCommand =
  1323. {
  1324.     if (deathmatch || coop)
  1325.         return;
  1326.  
  1327.     self.ammo_rockets = 100;
  1328.     self.ammo_nails = 200;
  1329.     self.ammo_shells = 100;
  1330.     self.items = self.items | 
  1331.         IT_AXE |
  1332.         IT_SHOTGUN |
  1333.         IT_SUPER_SHOTGUN |
  1334.         IT_NAILGUN |
  1335.         IT_SUPER_NAILGUN |
  1336.         IT_GRENADE_LAUNCHER |
  1337.         IT_ROCKET_LAUNCHER |
  1338.         IT_KEY1 | IT_KEY2;
  1339.  
  1340.     self.ammo_cells = 200;
  1341.     self.items = self.items | IT_LIGHTNING;
  1342.  
  1343.     self.weapon = IT_ROCKET_LAUNCHER;
  1344.     self.impulse = 0;
  1345.     W_SetCurrentAmmo ();
  1346. };
  1347.  
  1348. /*
  1349. ============
  1350. CycleWeaponCommand
  1351.  
  1352. Go to the next weapon with ammo
  1353. ============
  1354. */
  1355. void() CycleWeaponCommand =
  1356. {
  1357.     local   float   it, am;
  1358.     
  1359.     it = self.items;
  1360.     self.impulse = 0;
  1361.     
  1362.     while (1)
  1363.     {
  1364.         am = 0;
  1365.  
  1366.         if (self.weapon == IT_LIGHTNING)
  1367.         {
  1368.             self.weapon = IT_AXE;
  1369.         }
  1370.         else if (self.weapon == IT_AXE)
  1371.         {
  1372.             self.weapon = IT_SHOTGUN;
  1373.             if (self.ammo_shells < 1)
  1374.                 am = 1;
  1375.         }
  1376.         else if (self.weapon == IT_SHOTGUN)
  1377.         {
  1378.             self.weapon = IT_SUPER_SHOTGUN;
  1379.             if (self.ammo_shells < 2)
  1380.                 am = 1;
  1381.         }               
  1382.         else if (self.weapon == IT_SUPER_SHOTGUN)
  1383.         {
  1384.             self.weapon = IT_NAILGUN;
  1385.             if (self.ammo_nails < 1)
  1386.                 am = 1;
  1387.         }
  1388.         else if (self.weapon == IT_NAILGUN)
  1389.         {
  1390.             self.weapon = IT_SUPER_NAILGUN;
  1391.             if (self.ammo_nails < 2)
  1392.                 am = 1;
  1393.         }
  1394.         else if (self.weapon == IT_SUPER_NAILGUN)
  1395.         {
  1396.             self.weapon = IT_GRENADE_LAUNCHER;
  1397.             if (self.ammo_rockets < 1)
  1398.                 am = 1;
  1399.         }
  1400.         else if (self.weapon == IT_GRENADE_LAUNCHER)
  1401.         {
  1402.             self.weapon = IT_ROCKET_LAUNCHER;
  1403.             if (self.ammo_rockets < 1)
  1404.                 am = 1;
  1405.         }
  1406.         else if (self.weapon == IT_ROCKET_LAUNCHER)
  1407.         {
  1408.             self.weapon = IT_LIGHTNING;
  1409.             if (self.ammo_cells < 1)
  1410.                 am = 1;
  1411.         }
  1412.     
  1413.         if ( (self.items & self.weapon) && am == 0)
  1414.         {
  1415.             W_SetCurrentAmmo ();
  1416.             return;
  1417.         }
  1418.     }
  1419.  
  1420. };
  1421.  
  1422. /*
  1423. ============
  1424. ServerflagsCommand
  1425.  
  1426. Just for development
  1427. ============
  1428. */
  1429. void() ServerflagsCommand =
  1430. {
  1431.     serverflags = serverflags * 2 + 1;
  1432. };
  1433.  
  1434. void() QuadCheat =
  1435. {
  1436.     if (deathmatch || coop)
  1437.         return;
  1438.     self.super_time = 1;
  1439.     self.super_damage_finished = time + 30;
  1440.     self.items = self.items | IT_QUAD;
  1441.     dprint ("quad cheat\n");
  1442. };
  1443.  
  1444. /*
  1445. ============
  1446. ImpulseCommands
  1447.  
  1448. ============
  1449. */
  1450. void() ImpulseCommands =
  1451. {
  1452.     if (self.impulse >= 1 && self.impulse <= 8)
  1453.         W_ChangeWeapon ();
  1454.  
  1455.     if (self.impulse == 9)
  1456.         CheatCommand ();
  1457.     if (self.impulse == 10)
  1458.         CycleWeaponCommand ();
  1459.     if (self.impulse == 11)
  1460.         ServerflagsCommand ();
  1461.     
  1462.     // PATCH FOR BOUNCERS
  1463.     if (self.impulse == 20)
  1464.         W_LaunchBouncer ();
  1465.     
  1466.     if (self.impulse == 255)
  1467.         QuadCheat ();
  1468.         
  1469.     self.impulse = 0;
  1470. };
  1471.  
  1472. /*
  1473. ============
  1474. W_WeaponFrame
  1475.  
  1476. Called every frame so impulse events can be handled as well as possible
  1477. ============
  1478. */
  1479. void() W_WeaponFrame =
  1480. {
  1481.     if (time < self.attack_finished)
  1482.         return;
  1483.  
  1484.     ImpulseCommands ();
  1485.     
  1486. // check for attack
  1487.     if (self.button0)
  1488.     {
  1489.         SuperDamageSound ();
  1490.         W_Attack ();
  1491.     }
  1492. };
  1493.  
  1494. /*
  1495. ========
  1496. SuperDamageSound
  1497.  
  1498. Plays sound if needed
  1499. ========
  1500. */
  1501. void() SuperDamageSound =
  1502. {
  1503.     if (self.super_damage_finished > time)
  1504.     {
  1505.         if (self.super_sound < time)
  1506.         {
  1507.             self.super_sound = time + 1;
  1508.             sound (self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM);
  1509.         }
  1510.     }
  1511.     return;
  1512. };
  1513.  
  1514.  
  1515.